local _M = { }
local str_find = string.find
local ngx_re_match = ngx.re.match

function _M.challenge_MSIE(ua, result)
  if not str_find(ua, 'compatible; MSIE', 1, true) and not str_find(ua, 'Trident/', 1, true) and not str_find(ua, 'IEMobile/', 1, true) then
    return false;
  end

  local version = 'UNKNOWN'
  local match, err = ngx_re_match(ua, [[MSIE ([.0-9]+);]], "o")
  if match then
    version = match[1]
  else
    local match1, err1 = ngx_re_match(ua, [[Trident/([.0-9]+);]], "o")
    local match2, err2 = ngx_re_match(ua, [[ rv:([.0-9]+)]], "o")
    if match1 and match2 then
      version = match2[1]
    else
      match, err = ngx_re_match(ua, [[IEMobile/([.0-9]+);]], "o")
      if match then
        version = match[1]
      end
    end
  end
  result['browser'] = 'MSIE'
  result['browser_version'] = version
  return true;
end


function _M.challenge_safari_chrome(ua, result)
  if not str_find(ua, 'Safari/', 1, true) then
    return false
  elseif str_find(ua, 'Chrome', 1, true) and str_find(ua, 'wv', 1, true) then
    return false
  elseif str_find(ua, 'Google Web Preview', 1, true) then
    -- really????
    return false
  end

  local version = 'UNKNOWN'
  local match, err = ngx_re_match(ua, [[(?:Edge|Edg|EdgiOS|EdgA)\/([.0-9]+)]], "o")
  if match then
    version = match[1]
    result['browser'] = 'Edge'
    result['browser_version'] = version
    return true
  end

  local match, err = ngx_re_match(ua, [[FxiOS\/([.0-9]+)]], "o")
  if match then
    version = match[1]
    result['browser'] = 'Firefox'
    result['browser_version'] = version
    return true
  end

  local match, err = ngx_re_match(ua, [[(?:Chrome|CrMo|CriOS)/([.0-9]+)]], "o")
  if match then
    local match_ob, err = ngx_re_match(ua, [[OPR/([.0-9]+)]], "o")
    if match_ob then
      -- Opera w/ blink
      version = match_ob[1]
      result['browser'] = 'Opera'
      result['browser_version'] = version
      return true
    end

    -- Chrome
    version = match[1]
    result['browser'] = 'Chrome'
    result['browser_version'] = version
    return true
  end

  local match, err = ngx_re_match(ua, [[GSA\/([.0-9]+)]], "o")
  if match then
    version = match[1]
    result['browser'] = 'GSA'
    result['browser_version'] = version
    return true
  end

  local match, err = ngx_re_match(ua, [[Version/([.0-9]+)]], "o")
  if match then
    version = match[1]
  end
  result['browser'] = 'Safari'
  result['browser_version'] = version
  return true;
end


function _M.challenge_firefox(ua, result)
  if not str_find(ua, 'Firefox/', 1, true) then
    return false
  end

  local version = 'UNKNOWN'
  local match, err = ngx_re_match(ua, [[Firefox/([.0-9]+)]], "o")
  if match then
    version = match[1]
  end
  result['browser'] = 'Firefox'
  result['browser_version'] = version
  return true
end


function _M.challenge_yandexbrowser(ua, result)
  if not str_find(ua, 'YaBrowser/', 1, true) then
    return false
  end

  local version = 'UNKNOWN'
  local match, err = ngx_re_match(ua, [[YaBrowser/(\d+\.\d+\.\d+\.\d+)]], "o")
  if match then
    version = match[1]
  end
  result['browser'] = 'YaBrowser'
  result['browser_version'] = version
  return true
end


function _M.challenge_opera(ua, result)
  if not str_find(ua, 'Opera', 1, true) then
    return false
  end

  local version = 'UNKNOWN'
  local match, err = ngx_re_match(ua, [[Version/([.0-9]+)]], "o")
  if match then
    version = match[1]
  else
    local match, err = ngx_re_match(ua, [[Opera[/ ]([.0-9]+)]], "o")
    if match then
      version = match[1]
    end
  end
  result['browser'] = 'Opera'
  result['browser_version'] = version
  return true;
end
--国内几大浏览器特征
local browserKeys = {'NewsArticle','TTWebView','VivoBrowser','HuaweiBrowser','HeyTapBrowser','SogouMobileBrowser','UCBrowser','MiuiBrowser','MQQBrowser','baiduboxapp'}
function _M.challenge_webview(ua, result)
  local version = 'UNKNOWN'

  if str_find(ua, 'MicroMessenger', 1, true) then
    local match, err = ngx_re_match(ua, [[MicroMessenger/([.0-9]+)]], "o")
    if match then
      version = match[1]
    end
    result['browser'] = 'WeChat'
    result['browser_version'] = version
    return true
  end
  --通用特征识别
  for i=1,#browserKeys do
    if str_find(ua, browserKeys[i], 1, true) then
      local match, err = ngx_re_match(ua, browserKeys[i]..'/([.0-9]+)', "o")
      if match then
        version = match[1]
      end
      result['browser'] = browserKeys[i]
      result['browser_version'] = version
      return true
    end
  end

  if str_find(ua, 'Chrome', 1, true) and str_find(ua, 'wv', 1, true) then
    local match, err = ngx_re_match(ua, [[Version/([.0-9]+)]], "o")
    if match then
      version = match[1]
    end
    result['browser'] = 'Webview'
    result['browser_version'] = version
    return true
  end

  local match, err = ngx_re_match(ua, [[iP(?:hone;|ad;|od) (.*)like Mac OS X]], "o")
  if match then
    if str_find(ua, 'Safari/', 1, true) then
      return false
    end

    local match, err = ngx_re_match(ua, [[Version/([.0-9]+)]], "o")
    if match then
      version = match[1]
    end
    result['browser'] = 'Webview'
    result['browser_version'] = version
    return true
  end

  return false
end

function _M.challenge_sleipnir(ua, result)
  if not str_find(ua, 'Sleipnir/', 1, true) then
    return false
  end

  local version = 'UNKNOWN'
  local match, err = ngx_re_match(ua, [[Sleipnir/([.0-9]+)]], "o")
  if match then
    version = match[1]
  end
  result['browser'] = 'Sleipnir'
  result['browser_version'] = version

  -- [[
  --   Sleipnir's user-agent doesn't contain Windows version, so put 'Windows UNKNOWN Ver'.
  --   Sleipnir is IE component browser, so for Windows only.
  -- ]]
  result['os'] = 'Windows'
  return true
end

function _M.challenge_vivaldi(ua, result)
  if not str_find(ua, 'Vivaldi/', 1, true) then
    return false
  end

  local version = 'UNKNOWN'
  local match, err = ngx_re_match(ua, [[Vivaldi/([.0-9]+)]], "o")
  if match then
    version = match[1]
  end
  result['browser'] = 'Vivaldi'
  result['browser_version'] = version
  return true
end

function _M.challenge_samsung(ua, result)
  if not str_find(ua, 'SamsungBrowser/', 1, true) then
    return false
  end
  local version = 'UNKNOWN'
  local match, err = ngx_re_match(ua, [[SamsungBrowser/([.0-9]+)]], "o")
  if match then
    version = match[1]
  end
  result['browser'] = 'SamsungBrowser'
  result['browser_version'] = version
  return true
end

return _M
